﻿#region Usings

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Ninject;
using Rail.Net.Common;
using Rail.Net.Core.Interfaces.Data;
using Rail.Net.Core.Interfaces.Services;
using Rail.Net.Core.Model.Nonpersistent;
using Rail.Net.Services.EpaAnnullierung;
using Rail.Net.Services.EpaArzResInt;
using Rail.Net.Services.EpaArzResNat;
using Rail.Net.Services.EpaBestaetigung;
using Rail.Net.Services.EpaReservierung;
using Rail.Net.Services.EpaTarifverfuegbarkeit;
using Rail.Net.Services.EpaTarifverfuegbarkeit2;
using EpaVerfuegbarkeit_header = Rail.Net.Services.EpaTarifverfuegbarkeit.header;
using EpaVerfuegbarkeit_request_7_1 = Rail.Net.Services.EpaTarifverfuegbarkeit.request_7_1;
using EpaVerfuegbarkeit2_header = Rail.Net.Services.EpaTarifverfuegbarkeit2.header;
using EpaVerfuegbarkeit2_request_7_1 = Rail.Net.Services.EpaTarifverfuegbarkeit2.request_7_1;
using EpaReservierung_header_1_4 = Rail.Net.Services.EpaReservierung.header_1_4;
using EpaReservierung_request_7_3 = Rail.Net.Services.EpaReservierung.request_7_3;
using EpaBestaetigung_header_1_0 = Rail.Net.Services.EpaBestaetigung.header_1_0;
using EpaBestaetigung_request = Rail.Net.Services.EpaBestaetigung.request;
using EpaAnnullierung_header = Rail.Net.Services.EpaAnnullierung.header;
using EpaAnnullierung_request_7_1 = Rail.Net.Services.EpaAnnullierung.request_7_1;
using EpaArzResInt_header = Rail.Net.Services.EpaArzResInt.header;
using EpaArzResInt_request_7_3 = Rail.Net.Services.EpaArzResInt.request_7_3;
using EpaArzResNat_header = Rail.Net.Services.EpaArzResNat.header;
using EpaArzResNat_request_7_3 = Rail.Net.Services.EpaArzResNat.request_7_3;

#endregion

namespace Rail.Net.Services
{
    public class EpaService : IEpaService
    {
        private const string FirstClassLabels = "ALMNOPQRSTU";
        private const string SecondClassLabels = "BD4D6";

        [Inject]
        public IDalContext DalContext { get; set; }

        public List<Product2Model> GetPossibleProducts(int startIndex, SearchModel searchModel,
                                                       List<SequenceModel> sequences)
        {
            var result = new List<Product2Model>();
            var index = startIndex;

            foreach (var pair in Constants.GlobalComfortClassValues)
            {
                foreach (var label in pair.Value)
                {
                    var comfortClass = "0";
                    if (FirstClassLabels.Contains(label))
                    {
                        comfortClass = Constants.FirstClassNumber;
                    }
                    if (SecondClassLabels.Contains(label))
                    {
                        comfortClass = Constants.SecondClassNumber;
                    }
                    result.Add(new Product2Model(index++, searchModel, sequences, comfortClass)
                                   {
                                       ServiceLevelGroup = pair.Key,
                                       ServiceLevel = label
                                   });
                }
            }


            return result;
        }

        public void GetAvailability(SearchModel searchModel, GlobalSequenceModel sequence, List<Product2Model> products)
        {
            var fromRu = sequence.FromStation.Ru;
            var fromStation = sequence.FromStation.Epa;
            var toRu = sequence.ToStation.Ru;
            var toStation = sequence.ToStation.Epa;

            var trains = new List<string> { sequence.GlobalTrain.Number.PadRight(5, ' ') };
            if (sequence.GlobalTrain.Number == "235")
            {
                trains.Add("60" + sequence.GlobalTrain.Number);
            }
            
            var departureDate = sequence.GlobalTrain.Departure.DepartureTime.ToString(Constants.GlobalDateFormat);
            var route = string.Format("{0}-{1}", fromRu, toRu);

            foreach (var train in trains)
            {
                var trainNumber = train;
                foreach (var globalComfortClass in Constants.GlobalComfortClasses)
                {
                    var @class = globalComfortClass.PadRight(3, ' ');
                    Task.Factory.StartNew(
                        () =>
                        GetAvailabilityWebServiceCall(searchModel, sequence, products, fromStation, toStation,
                                                      trainNumber, departureDate, route, @class),
                        TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent);

                    if (!Constants.GlobalInversedTrains.ContainsKey(sequence.GlobalTrain.Number))
                        continue;

                    var newTrainNumber = Constants.GlobalInversedTrains[sequence.GlobalTrain.Number].PadRight(5, ' ');
                    Task.Factory.StartNew(
                        () =>
                        GetAvailabilityWebServiceCall(searchModel, sequence, products, toStation, fromStation,
                                                      newTrainNumber, departureDate, route, @class, true),
                        TaskCreationOptions.LongRunning | TaskCreationOptions.AttachedToParent);
                }
            }
        }

        private static void GetAvailabilityWebServiceCall(SearchModel searchModel,
                                                   GlobalSequenceModel sequence,
                                                   List<Product2Model> products,
                                                   string fromStation,
                                                   string toStation,
                                                   string trainNumber,
                                                   string departureDate,
                                                   string route,
                                                   string comfortClass,
                                                   bool inversed = false)
        {
            try
            {
                var header = new EpaVerfuegbarkeit_header
                {
                    servicekey = 227,
                    lenheader = 12,
                    lenbuf = 62,
                    maxreply = 4188
                };
                var service = new EPATARIFVERFUEGBARKEITService();
                var request = new EpaVerfuegbarkeit_request_7_1
                {
                    abt_charak = "0",
                    abteilart = "000000",
                    aut_dab = "0",
                    aut_mgg = "0",
                    aut_stoffdach = "0",
                    datum_ab = departureDate,
                    dialognr = "888888",
                    dienstleistung = comfortClass,
                    gruppe = "0",
                    terminalnr = "952001",
                    zugnr = trainNumber,
                    service = "00",
                    anzahl = searchModel.Travelers.Count.ToString("00"),
                    bh_von_nr = fromStation,
                    bh_nach_nr = toStation,
                    programmnr = "227",
                    vkz = "99"
                };

                var result = service.EPATARIFVERFUEGBARKEIT(new EPATARIFVERFUEGBARKEIT
                {
                    header = header,
                    request = request
                });
                if (result.request != null)
                {
                    var slTarifs = new List<string>();
                    var response = result.request;
                    var productCount = Int32.Parse(response.anz_pi);
                    var offersCount = Int32.Parse(response.anz_ag);


                    var fullPriceCodes = Constants.GlobalFullTarifs[route];
                    var childPriceCodes = Constants.GlobalChildTarifs[route];
                    var discountPriceCodes = Constants.GlobalDiscountTarifs[route];


                    for (var i = 0; i < productCount; i++)
                    {
                        var pid = Int32.Parse(response.produkte.Substring(i * 24, 2));
                        var sl = response.produkte.Substring(i * 24 + 2, 2).Trim();

                        // if valid comfort class
                        if (
                            Constants.GlobalComfortClassValues[Constants.ServiceLevelSeat].Contains(sl) ||
                            Constants.GlobalComfortClassValues[Constants.ServiceLevelCouchette].Contains(sl) ||
                            Constants.GlobalComfortClassValues[Constants.ServiceLevelSleepWagon].Contains(sl))
                        {
                            var minPriceFullTarif = 0m;
                            var minPriceChildTarif = 0m;
                            var minPriceDiscountTarif = 0m;

                            // find the correspondng product
                            var product = products.FirstOrDefault(p => p.ServiceLevel.Trim() == sl.Trim());
                            var priceSegment = product.GetPriceSegmentForSequence(sequence);
                            for (var j = 0; j < offersCount; j++)
                            {
                                var aid = Int32.Parse(response.angebote.Substring(j * 14, 2));
                                if (aid != 0 && pid == aid)
                                {
                                    int freeSeats;
                                    int.TryParse(response.angebote.Substring(j * 14 + 2, 2), out freeSeats);
                                    var tarif = response.angebote.Substring(j * 14 + 4, 2);
                                    decimal price;
                                    decimal.TryParse(response.angebote.Substring(j * 14 + 6, 7), out price);
                                    if (price > 0m)
                                    {
                                        price = price / 100;
                                    }

                                    if (!inversed)
                                    {
                                        priceSegment.NumberOfFreeSeats = freeSeats;
                                    }

                                    var key = string.Format("{0}_{1}", sl, tarif);
                                    if (!slTarifs.Contains(key) && price != 0m)            
                                    {
                                        if ((minPriceFullTarif == 0m || price < minPriceFullTarif) && fullPriceCodes.Contains(tarif))
                                        {
                                            minPriceFullTarif = price;
                                            priceSegment.PricesProTravelerGrownup.ForEach(p => { p.Price = price; });
                                        }
                                        if ((minPriceChildTarif == 0m || price < minPriceChildTarif) && childPriceCodes.Contains(tarif))
                                        {
                                            minPriceChildTarif = price;
                                            priceSegment.PricesProTravelerChild.ForEach(p => { p.Price = price; });
                                        }
                                        if ((minPriceDiscountTarif == 0m || price < minPriceDiscountTarif) && discountPriceCodes.Contains(tarif))
                                        {
                                            minPriceDiscountTarif = price;
                                            priceSegment.PricesProTravelerDiscount.ForEach(p => { p.Price = price; });
                                        }

                                        slTarifs.Add(key);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                var a = 9;
            }
        }

        public void GetAvailabilityTest()
        {
            var service = new EPATARIFVERFUEGBARKEITService();
            var result = service.EPATARIFVERFUEGBARKEIT(new EPATARIFVERFUEGBARKEIT
                                                            {
                                                                header = new EpaVerfuegbarkeit_header
                                                                             {
                                                                                 servicekey = 227,
                                                                                 lenheader = 12,
                                                                                 lenbuf = 62,
                                                                                 maxreply = 4188
                                                                             },
                                                                request = new EpaVerfuegbarkeit_request_7_1
                                                                              {
                                                                                  abt_charak = "0",
                                                                                  abteilart = "000000",
                                                                                  aut_dab = "0",
                                                                                  aut_mgg = "0",
                                                                                  aut_stoffdach = "0",
                                                                                  datum_ab = "20112011",
                                                                                  dialognr = "888888",
                                                                                  dienstleistung = "SE ",
                                                                                  gruppe = "0",
                                                                                  terminalnr = "952001",
                                                                                  // 952001
                                                                                  zugnr = "490  ",
                                                                                  service = "00",
                                                                                  anzahl = "01",
                                                                                  bh_nach_nr = "8020402",
                                                                                  bh_von_nr = "8100101",
                                                                                  programmnr = "227",
                                                                                  vkz = "99"
                                                                              }
                                                            });
            if (result.request != null)
            {
                var slTarifs = new List<string>();
                var request = result.request;
                var productCount = Int32.Parse(request.anz_pi);
                var offersCount = Int32.Parse(request.anz_ag);

                var culture = CultureInfo.InvariantCulture;
                var departure = DateTime.ParseExact(request.datum_ab + request.zeit_ab, "ddMMyyyyHHmm", culture);
                var arrival = DateTime.ParseExact(request.datum_an + request.zeit_an, "ddMMyyyyHHmm", culture);


                for (var i = 0; i < productCount; i++)
                {
                    var pid = Int32.Parse(request.produkte.Substring(i*24, 2));
                    var sl = request.produkte.Substring(i*24 + 2, 2).Trim();

                    for (var j = 0; j < offersCount; j++)
                    {
                        var aid = Int32.Parse(request.angebote.Substring(j*14, 2));
                        if (aid != 0 && pid == aid)
                        {
                            var freeSeats = request.angebote.Substring(j*14 + 2, 2);
                            var tarif = request.angebote.Substring(j*14 + 4, 2);
                            var price = Int32.Parse(request.angebote.Substring(j*14 + 6, 7));
                            const string seats = "AB";
                            const string couchette = "D4D6";
                            const string sleepWagons = "LMNPQRSTU";

                            if (seats.Contains(sl) || couchette.Contains(sl) || sleepWagons.Contains(sl))
                            {
                                var key = string.Format("{0}_{1}", sl, tarif);
                                if (!slTarifs.Contains(key))
                                {
                                    //
                                    // create product
                                    //var product = new ProductModel(0, 1, null, sl);

                                    slTarifs.Add(key);
                                }
                            }
                        }
                    }
                }
            }
        }

        public void GetAvailability2()
        {
            var service = new EPATARIFVERFUEGBARKEIT2Service();
            var result = service.EPATARIFVERFUEGBARKEIT2(new EPATARIFVERFUEGBARKEIT2
                                                             {
                                                                 header = new EpaVerfuegbarkeit2_header
                                                                              {
                                                                                  servicekey = 402,
                                                                                  lenheader = 12,
                                                                                  lenbuf = 596,
                                                                                  maxreply = 1130
                                                                              },
                                                                 request = new EpaVerfuegbarkeit2_request_7_1
                                                                               {
                                                                                   abt_charak = "",
                                                                                   abteilart = "",
                                                                                   aut_dab = "",
                                                                                   aut_mgg = "",
                                                                                   aut_stoffdach = "",
                                                                                   datum_ab = "",
                                                                                   dialognr = "",
                                                                                   dienstleistung = "",
                                                                                   gruppe = "",
                                                                                   terminalnr = "",
                                                                                   zugnr = "",
                                                                                   service = "",
                                                                                   anzahl = "",
                                                                                   bh_nach_nr = "",
                                                                                   bh_von_nr = "",
                                                                                   programmnr = "",
                                                                                   vkz = "",
                                                                                   alle = "",
                                                                                   anzahl1 = "",
                                                                                   anzahl2 = "",
                                                                                   tage = "",
                                                                                   tarif1 = "",
                                                                                   tarif2 = "",
                                                                                   zugnr2 = "",
                                                                                   zugnr3 = "",
                                                                                   zugnr4 = ""
                                                                               }
                                                             });
        }

        public void Reservation()
        {
            var service = new EPARESERVIERUNGService();
            var result = service.EPARESERVIERUNG(new EPARESERVIERUNG
                                                     {
                                                         header = new EpaReservierung_header_1_4
                                                                      {
                                                                          servicekey = 402,
                                                                          lenheader = 12,
                                                                          lenbuf = 596,
                                                                          maxreply = 1130
                                                                      },
                                                         request = new EpaReservierung_request_7_3
                                                                       {
                                                                           abt_charak = "",
                                                                           abteilart = "",
                                                                           abteillage = "",
                                                                           anderer_zug = "",
                                                                           anz_bett = "",
                                                                           anzahl = "",
                                                                           anzahl_fahrrad = "",
                                                                           bez_platz = "",
                                                                           bh_nach_nr = "",
                                                                           bh_von_nr = "",
                                                                           buchungsnr = "",
                                                                           datum_ab = "",
                                                                           dienstleistung = "",
                                                                           einzel_f = "",
                                                                           fahrtkode = "",
                                                                           fenster_oben = "",
                                                                           filler = "",
                                                                           gang_unten = "",
                                                                           gruppe = "",
                                                                           klasse = "",
                                                                           mitte = "",
                                                                           pers_tarif = "",
                                                                           platzlage2 = "",
                                                                           platznr_best = "",
                                                                           programmnr = "",
                                                                           r_n = "",
                                                                           res_entg_kz = "",
                                                                           tarif = "",
                                                                           tarif2 = "",
                                                                           terminalnr = "",
                                                                           unbedingt_f_u = "",
                                                                           verbindungstuer = "",
                                                                           vkz = "",
                                                                           wagen = "",
                                                                           zugnr = ""
                                                                       }
                                                     });
        }

        public void Confirmation()
        {
            var service = new EPA_BESTAETIGUNGService();
            var result = service.EPA_BESTAETIGUNG(new EPA_BESTAETIGUNG
                                                      {
                                                          header = new EpaBestaetigung_header_1_0
                                                                       {
                                                                           servicekey = 402,
                                                                           lenheader = 12,
                                                                           lenbuf = 596,
                                                                           maxreply = 1130
                                                                       },
                                                          request = new EpaBestaetigung_request
                                                                        {
                                                                            buchungs_nr = "",
                                                                            datum = "",
                                                                            referenz_nr = "",
                                                                            reject = "",
                                                                            terminal_nr = "",
                                                                            zug_nr = ""
                                                                        }
                                                      });
        }

        public void Rollback()
        {
            var service = new EPAANNULLIERUNGService();
            var result = service.EPAANNULLIERUNG(new EPAANNULLIERUNG
                                                     {
                                                         header = new EpaAnnullierung_header
                                                                      {
                                                                          servicekey = 402,
                                                                          lenheader = 12,
                                                                          lenbuf = 596,
                                                                          maxreply = 1130
                                                                      },
                                                         request = new EpaAnnullierung_request_7_1
                                                                       {
                                                                           buchungsnr = "",
                                                                           datum_ab = "",
                                                                           dienstleistung = "",
                                                                           geb_frei_annull = "",
                                                                           grund = "",
                                                                           programmnr = "",
                                                                           referenznr = "",
                                                                           terminalnr = "",
                                                                           vkz = "",
                                                                           zugnr = ""
                                                                       }
                                                     });
        }

        public void CarTransportationInternational()
        {
            var service = new EPAARZRESINTService();
            var result = service.EPAARZRESINT(new EPAARZRESINT
                                                  {
                                                      header = new EpaArzResInt_header
                                                                   {
                                                                       servicekey = 402,
                                                                       lenheader = 12,
                                                                       lenbuf = 596,
                                                                       maxreply = 1130
                                                                   },
                                                      request = new EpaArzResInt_request_7_3
                                                                    {
                                                                        abt_charak = "",
                                                                        abteilart = "",
                                                                        abteillage = "",
                                                                        anderer_zug = "",
                                                                        anzahl = "",
                                                                        anzahl_double = "",
                                                                        anzahl_fahrrad = "",
                                                                        anzahl_single = "",
                                                                        anzahl_spezial = "",
                                                                        anzahl_t2 = "",
                                                                        anzahl_t3 = "",
                                                                        anzahl_t4 = "",
                                                                        aut_and_zug = "",
                                                                        aut_anh_b = "",
                                                                        aut_anh_h = "",
                                                                        aut_anh_kat = "",
                                                                        aut_anh_kz = "",
                                                                        aut_anh_l = "",
                                                                        aut_antragst_bahn = "",
                                                                        aut_bh_nach_nr = "",
                                                                        aut_bh_von_nr = "",
                                                                        aut_boot_kat = "",
                                                                        aut_dab = "",
                                                                        aut_dab_art = "",
                                                                        aut_dab_h = "",
                                                                        aut_datum = "",
                                                                        aut_dl = "",
                                                                        aut_fahrtcode = "",
                                                                        aut_fahrtnr = "",
                                                                        aut_kfz_b = "",
                                                                        aut_kfz_h = "",
                                                                        aut_kfz_kat = "",
                                                                        aut_kfz_kz = "",
                                                                        aut_kfz_l = "",
                                                                        aut_kfz_typ = "",
                                                                        aut_kundenname = "",
                                                                        aut_mgg = "",
                                                                        aut_mgg_anz = "",
                                                                        aut_nur_kfz_preis = "",
                                                                        aut_stoffdach = "",
                                                                        aut_tarif1 = "",
                                                                        aut_tarif2 = "",
                                                                        aut_tel_kz = "",
                                                                        aut_vorgangsnr = "",
                                                                        aut_zugnr = "",
                                                                        bh_nach_nr = "",
                                                                        bh_von_nr = "",
                                                                        buchungsnr = "",
                                                                        datum = "",
                                                                        dienstleistung = "",
                                                                        einzel_f = "",
                                                                        fenster_oben = "",
                                                                        filler = "",
                                                                        gang_unten = "",
                                                                        klasse = "",
                                                                        mitte = "",
                                                                        pers_tarif = "",
                                                                        platzlage2 = "",
                                                                        programmnr = "",
                                                                        r_n = "",
                                                                        res_entg_kz = "",
                                                                        tarif = "",
                                                                        tarif2 = "",
                                                                        terminalnr = "",
                                                                        unbedingt_f_u = "",
                                                                        verbindungstuer = "",
                                                                        vkz = "",
                                                                        zugnr = ""
                                                                    }
                                                  });
        }

        public void CarTransportationNational()
        {
            var service = new EPAARZRESNATService();
            var result = service.EPAARZRESNAT(new EPAARZRESNAT
                                                  {
                                                      header = new EpaArzResNat_header
                                                                   {
                                                                       servicekey = 402,
                                                                       lenheader = 12,
                                                                       lenbuf = 596,
                                                                       maxreply = 1130
                                                                   },
                                                      request = new EpaArzResNat_request_7_3
                                                                    {
                                                                        abteilart = "",
                                                                        anzahl = "",
                                                                        arz_anh_b = "",
                                                                        arz_anh_h = "",
                                                                        arz_anh_kat = "",
                                                                        arz_anh_l = "",
                                                                        arz_dab_h = "",
                                                                        arz_datum = "",
                                                                        arz_dl = "",
                                                                        arz_kfz_b = "",
                                                                        arz_kfz_h = "",
                                                                        arz_kfz_kat = "",
                                                                        arz_kfz_kz = "",
                                                                        arz_kfz_l = "",
                                                                        arz_kfz_typ = "",
                                                                        arz_kundenname = "",
                                                                        arz_stoffdach = "",
                                                                        arz_zugnr = "",
                                                                        bh_nach_nr = "",
                                                                        bh_von_nr = "",
                                                                        buchungsnr = "",
                                                                        dienstleistung = "",
                                                                        fenster_oben = "",
                                                                        gang_unten = "",
                                                                        klasse = "",
                                                                        mitte = "",
                                                                        pers_tarif = "",
                                                                        programmnr = "",
                                                                        r_n = "",
                                                                        tarif = "",
                                                                        terminalnr = "",
                                                                        unbedingt_f_u = "",
                                                                        vkz = "",
                                                                        zugnr = "",
                                                                        kfz = "",
                                                                        relationsnr = ""
                                                                    }
                                                  });
        }
    }
}